← All Articles

[BAEKJOON] 1103. 게임

Posted on

문제 :

형택이는 1부터 9까지의 숫자와, 구멍이 있는 직사각형 보드에서 재밌는 게임을 한다.

일단 보드의 가장 왼쪽 위에 동전을 하나 올려놓는다. 그다음에 다음과 같이 동전을 움직인다.

  1. 동전이 있는 곳에 쓰여 있는 숫자 X를 본다.
  2. 위, 아래, 왼쪽, 오른쪽 방향 중에 한가지를 고른다.
  3. 동전을 위에서 고른 방향으로 X만큼 움직인다. 이때, 중간에 있는 구멍은 무시한다.

만약 동전이 구멍에 빠지거나, 보드의 바깥으로 나간다면 게임은 종료된다. 형택이는 이 재밌는 게임을 되도록이면 오래 하고 싶다.

보드의 상태가 주어졌을 때, 형택이가 최대 몇 번 동전을 움직일 수 있는지 구하는 프로그램을 작성하시오.


입력 :

줄에 보드의 세로 크기 N과 가로 크기 M이 주어진다. 이 값은 모두 50보다 작거나 같은 자연수이다. 둘째 줄부터 N개의 줄에 보드의 상태가 주어진다. 쓰여 있는 숫자는 1부터 9까지의 자연수 또는 H이다. 가장 왼쪽 위칸은 H가 아니다. H는 구멍이다.


출력 :

첫째 줄에 문제의 정답을 출력한다. 만약 형택이가 동전을 무한번 움직일 수 있다면 -1을 출력한다.




풀이 :

문제를 초반에 너무 어렵게 접근한 탓에 로직을 다듬느라 시간이 많이 걸린 문제였다.

문제는 생각보단 단순하다. 무난하게 경로를 탐색하면 되는 문제인데 조금 다른 점이 있다면 동전이 무한하게 움직일 경우를 선별해낼 수 있어야 한다.

초반부터 무한히 움직일 경우는 밟은 칸을 다시 밟게 되는 경우라고 정리할 수 있었지만 그 점을 어떻게 구현할지 생각하는데 좀 헷갈리는 점이 몇 군데 있었다.

결론적으로 말하자면 내가 구현한 방식은 visit 배열과 dp 배열을 모두 사용한 dfs 방식으로 문제를 해결했다.

  • dfs 방식으로 깊이 탐색을 통해 경로를 찾아본다.
  • visit 배열을 말 그대로 해당 칸을 탐색하는 과정에서 한 번이라도 밟은 적이 있는지 체크하는 용도이다.
  • dp 배열은 크게 두가지 기능을 한다. 먼저 기본적으로 해당 칸을 탐색한 적이 있다면 해당 칸의 최대 깊이(최대 이동 횟수)를 저장하는 용도로 쓰인다.
  • dp 배열의 두번째 기능으로는 무한 경로인지 아닌지 체크하는 용도이다. dp 배열은 초반 0으로 모두 초기화 되어있는데 만약 visit 배열에서는 true로 방문한 적이 있는 칸인데 dp 배열이 그대로 0이란 말은 현재 dfs의 한 경로에서 중복적으로 방문했다는 말이기 때문에 무한 경로로 판단하게 되는 것이다.



코드 :

코드 보기/접기
#include <iostream>
#include <algorithm>

using namespace std;
char map[50][50];
bool visit[50][50];
int n, m, di[4] = {0, 1, 0, -1}, dj[4] = {1, 0, -1, 0}, dp[50][50];

int dfs(int x, int y) {
    if (visit[x][y]) {
        if (dp[x][y]) return dp[x][y];
        return -1;
    }

    int move = map[x][y] - '0', result, curcnt = 0;
    visit[x][y] = true;
    for (int k = 0; k < 4; k++) {
        int cmpx = x + move * di[k], cmpy = y + move * dj[k];
        if (0 <= cmpx && cmpx < n && 0 <= cmpy && cmpy < m) {
            if (map[cmpx][cmpy] == 'H') continue;
            result = dfs(cmpx, cmpy);
            if (result == -1) return -1;
            curcnt = max(curcnt, result);
        }
    }
    return dp[x][y] = curcnt + 1;
}

int main() {
    cin >> n >> m;
    for (int i = 0; i < n; i++)
        for (int j = 0; j < m; j++)
            cin >> map[i][j];
    cout << dfs(0, 0) << '\n';
    return 0;
}

AlgorithmalgorithmbaekjoonC++